package com.sky.controller.mirror;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.IPage;
import com.sky.constant.JwtClaimsConstant;
import com.sky.dto.futu.AccTradingInfoRequestDto;
import com.sky.dto.futu.ModifyOrderRequestDto;
import com.sky.dto.futu.PlaceOrderRequestDto;
import com.sky.dto.futu.PositionListRequestDto;
import com.sky.entity.futu.*;
import com.sky.properties.JwtProperties;
import com.sky.service.StockOptionService;
import com.sky.service.StockOrderService;
import com.sky.service.impl.*;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/trading")
@Api(tags = "富途交易相关接口")
public class TradingController {

    private final FutuAccountService futuAccountService;

    private final FutuFundPositionService futuFundPositionService;

    private final FutuOrderService futuOrderService;

    private final FutuDealService futuDealService;

    private final FutuMarketService futuMarketService;

    private final JwtProperties jwtProperties;

    @Autowired
    private StockOrderService stockOrderService;

    @Autowired
    private StockOptionService stockOptionService;

    @Autowired
    public TradingController(FutuAccountService futuAccountService,
                             FutuFundPositionService futuFundPositionService,
                             FutuOrderService futuOrderService, FutuDealService futuDealService,
                             FutuMarketService futuMarketService,
                             JwtProperties jwtProperties) {
        this.futuAccountService = futuAccountService;
        this.futuFundPositionService = futuFundPositionService;
        this.futuOrderService = futuOrderService;
        this.futuDealService = futuDealService;
        this.futuMarketService = futuMarketService;
        this.jwtProperties = jwtProperties;
    }

    @ApiOperation("获取账户列表")
    @GetMapping("/accounts")
    public R getAccountList() throws IOException {
        return R.ok(futuAccountService.getAccountList());
    }

    @ApiOperation("获取资金信息")
    @GetMapping("/info")
    public R getInfo() throws IOException {
        return R.ok(futuFundPositionService.getInfo());
    }

    @ApiOperation("获取持仓列表")
    @PostMapping("/getPositionList")
    public R getPositionList(@RequestBody PositionListRequestDto requestDto) throws IOException {
        return R.ok(futuFundPositionService.getPositionList(requestDto.getCode(), requestDto.getPlRatioMin(), requestDto.getPlRatioMax()));
    }

    @ApiOperation("查询最大可买可卖")
    @PostMapping("/getAccTradingInfo")
    public R getAccTradingInfo(@RequestBody AccTradingInfoRequestDto requestDto) throws IOException {
        return R.ok(futuFundPositionService.getAccTradingInfo(requestDto.getOrderType(), requestDto.getCode(), requestDto.getPrice(), requestDto.getOrderId()));
    }

    @ApiOperation("获取历史订单记录")
    @GetMapping("/orders")
    public R getHistoryOrders(@RequestParam(required = false) String code,
                              @RequestParam(required = false) String start,
                              @RequestParam(required = false) String end) throws IOException {
        return R.ok(futuOrderService.getHistoryOrders(code, start, end));
    }

    @ApiOperation("查询单个或多个订单费用")
    @GetMapping("/getOrdersFee")
    public R getOrdersFee(@RequestParam String order_id_list) throws IOException {
        return R.ok(futuOrderService.getOrderFee(order_id_list));
    }

    @ApiOperation("查询未完成订单")
    @GetMapping("/get_order_list")
    public R get_order_list(@RequestParam(required = false) String order_id,
                            @RequestParam(required = false) String code,
                            @RequestParam(required = false) String start,
                            @RequestParam(required = false) String end) throws IOException {
        return R.ok(futuOrderService.getOrderList(order_id, code, start, end));
    }

    /**
     * @param placeOrderRequestDto String code, String trd_side, String qty, String price
     *                             code     标的代码
     *                             trd_side 交易方向，0未知，1买入，2卖出，3卖空，4买回
     *                             qty      订单数量
     *                             price    订单价格
     * @return
     * @throws IOException
     */
    @ApiOperation("下单")
    @PostMapping("/place_order")
    // String code, String trd_side, String qty, String price
    public R place_order(@RequestBody PlaceOrderRequestDto placeOrderRequestDto) throws IOException {
        return R.ok(futuOrderService.placeOrder(placeOrderRequestDto));
    }

    @ApiOperation("子账号下单")
    @PostMapping("/place_order_sub")
    // String code, String trd_side, String qty, String price
    public R place_order_sub(HttpServletRequest request, @RequestBody PlaceOrderRequestDto placeOrderRequestDto) throws IOException {
        String token = request.getHeader(jwtProperties.getSubAccountsTokenName());
        Claims claims = JwtUtil.parseJWT(jwtProperties.getSubAccountsSecretKey(), token);
        String userId = claims.get(JwtClaimsConstant.ACCOUNT_ID).toString();
        // todo 存入下单后用户关联的订单 order_id
        List<OrderPlace> orderPlaces = futuOrderService.placeOrder(placeOrderRequestDto);
        OrderPlace orderPlace = orderPlaces.get(0);
        StockOrder stockOrder = new StockOrder();
        stockOrder.setCreateTime(LocalDateTime.now());
        stockOrder.setStatus(0);
        stockOrder.setUserId(Long.parseLong(userId));
        stockOrder.setOrderId(orderPlace.getOrder_id());
        stockOrder.setStockCode(orderPlace.getCode());
        stockOrder.setStockName(orderPlace.getStock_name());
        stockOrder.setStockType(1);
        stockOrder.setOrderType(1);
        stockOrder.setPrice(Double.parseDouble(orderPlace.getPrice()));
        stockOrder.setNumber(Integer.parseInt(orderPlace.getQty()));
        // todo 暂时Freeze计算为 成本买入价 + 5HKD，即假设手续费为5港币
        stockOrder.setFreeze(Double.parseDouble(orderPlace.getPrice()) * Integer.parseInt(orderPlace.getQty()) + 5D);
        stockOrder.setRealPrice(Double.parseDouble(orderPlace.getPrice()) * Integer.parseInt(orderPlace.getQty()));
        // todo 暂时没想好持仓这块要怎么办？方案：检测到订单从提交 -> 成交后，根据订单信息凭空捏造一个持仓item，并关联富途数据库中的持仓item id，且同item id所对应的每个捏造item持仓数不得大于富途里的item
        stockOrder.setHoldingId(null);
        return R.ok(stockOrderService.save(stockOrder));
    }


    @ApiOperation("改单1撤单2")
    @PostMapping("/modify_order")
    // String code, String trd_side, String qty, String price
    public R modify_order(@RequestBody ModifyOrderRequestDto modifyOrderRequestDto) throws IOException {
        return R.ok(futuOrderService.modifyOrder(modifyOrderRequestDto));
    }


    @ApiOperation("获取历史成交")
    @GetMapping("/history_deal")
    public R history_deal(@RequestParam(required = false) String code, @RequestParam(required = false) String start, @RequestParam(required = false) String end) throws IOException {
        return R.ok(futuDealService.getHistoryDeals(code, start, end));
    }

    @ApiOperation("获取今日成交")
    @GetMapping("/today_deal")
    public R today_deal(@RequestParam(required = false) String code) throws IOException {
        return R.ok(futuDealService.getTodayDeals(code));
    }

    @ApiOperation("获取期权链列表")
    @GetMapping("/get_quotes_list")
    public R get_quotes_list(@RequestParam String code) throws IOException {
        return R.ok(futuMarketService.getQuotesList(code));
    }

    @ApiOperation("添加期权到订阅列表")
    @PostMapping("/add_quote")
    public R add_quote(@RequestBody StockOption stockOption) throws IOException {
        return R.ok(stockOptionService.save(stockOption));
    }

    @ApiOperation("分页期权列表")
    @GetMapping("/page_quote")
    public R add_quote(@RequestParam(value = "code", required = false) String code, @RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "size", defaultValue = "20") Integer size) throws IOException {
        Page<StockOption> optionPage = new Page<>(page, size);
        LambdaQueryWrapper<StockOption> stockOptionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (!code.isEmpty()) {
            stockOptionLambdaQueryWrapper.eq(StockOption::getCode, code);
        }
        return R.ok(stockOptionService.page(optionPage, stockOptionLambdaQueryWrapper));
    }
}
